package com.nanhai.buddhist.college.module.collegebase.service.classes;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.nanhai.buddhist.college.framework.common.exception.util.ServiceExceptionUtil;
import com.nanhai.buddhist.college.framework.common.pojo.PageResult;
import com.nanhai.buddhist.college.framework.common.util.collection.CollectionUtils;
import com.nanhai.buddhist.college.framework.common.util.number.NumberUtils;
import com.nanhai.buddhist.college.framework.datapermission.core.annotation.DataPermission;
import com.nanhai.buddhist.college.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.nanhai.buddhist.college.framework.security.core.util.SecurityFrameworkUtils;
import com.nanhai.buddhist.college.module.collegebase.api.collegeclass.dto.ClassesTeacherDTO;
import com.nanhai.buddhist.college.module.collegebase.api.collegeclass.vo.ClassesInfoDTOPageVO;
import com.nanhai.buddhist.college.module.collegebase.controller.admin.classes.vo.ClassesCreateReqVO;
import com.nanhai.buddhist.college.module.collegebase.controller.admin.classes.vo.ClassesExportReqVO;
import com.nanhai.buddhist.college.module.collegebase.controller.admin.classes.vo.ClassesPageReqVO;
import com.nanhai.buddhist.college.module.collegebase.controller.admin.classes.vo.ClassesUpdateReqVO;
import com.nanhai.buddhist.college.module.collegebase.convert.classes.ClassesConvert;
import com.nanhai.buddhist.college.module.collegebase.dal.dataobject.classes.ClassesDO;
import com.nanhai.buddhist.college.module.collegebase.dal.dataobject.classes.ClassesInfoDO;
import com.nanhai.buddhist.college.module.collegebase.dal.dataobject.classes.ClassesTeacherDO;
import com.nanhai.buddhist.college.module.collegebase.dal.dataobject.classes.CollegeAndClassesDO;
import com.nanhai.buddhist.college.module.collegebase.dal.dataobject.professions.ProfessionsDO;
import com.nanhai.buddhist.college.module.collegebase.dal.dataobject.studentroll.StudentRollDO;
import com.nanhai.buddhist.college.module.collegebase.dal.dataobject.teacherteachers.TeacherTeachersDO;
import com.nanhai.buddhist.college.module.collegebase.dal.mysql.classes.ClassesMapper;
import com.nanhai.buddhist.college.module.collegebase.dal.mysql.classes.ClassesTeacherMapper;
import com.nanhai.buddhist.college.module.collegebase.dal.mysql.colleges.CollegesMapper;
import com.nanhai.buddhist.college.module.collegebase.dal.mysql.professions.ProfessionsMapper;
import com.nanhai.buddhist.college.module.collegebase.dal.mysql.studentroll.StudentRollMapper;
import com.nanhai.buddhist.college.module.collegebase.dal.mysql.teacherteachers.TeacherTeachersMapper;
import com.nanhai.buddhist.college.module.collegebase.enums.ErrorCodeConstants;
import com.nanhai.buddhist.college.module.collegebase.util.DateChangeUtil;
import com.nanhai.buddhist.college.module.system.api.user.AdminUserApi;
import com.xkcoding.http.util.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 学校管理-班级 Service 实现类
 *
 * @author 开发
 */
@Service
@Validated
public class ClassesServiceImpl implements ClassesService {

    @Resource
    private ClassesMapper classesMapper;

    @Resource
    private StudentRollMapper studentRollMapper;

    @Resource
    private ProfessionsMapper professionsMapper;


    @Resource
    private ClassesTeacherMapper classesTeacherMapper;

    @Resource
    private TeacherTeachersMapper teacherTeachersMapper;

    @Resource
    private AdminUserApi adminUserApi;

    @Resource
    private CollegesMapper collegesMapper;


    @Override
    public String createClasses(ClassesCreateReqVO createReqVO) {

        final Long count = classesMapper.selectCount(new LambdaQueryWrapper<ClassesDO>()
                .eq(ClassesDO::getProfessionId, createReqVO.getProfessionId())
                .eq(ClassesDO::getClassesName, createReqVO.getClassesName()));
        if (ObjectUtil.isNotNull(count) && count > 0) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.CLASSES_NAME_HAVE_EXISTS);
        }
        // 插入
        ClassesDO classes = ClassesConvert.INSTANCE.convert(createReqVO);
        String codeString = getCodeString(createReqVO);
        classes.setClassesCode(codeString);
        classes.setClassesNumber(NumberUtils.getCodeByServ("BJ"));


        classesMapper.insert(classes);

        ClassesTeacherDO build = ClassesTeacherDO.builder().classesId(classes.getId()).teacherId(createReqVO.getClassTeacherName()).teacherUserType(1).build();
        ClassesTeacherDO build1 = ClassesTeacherDO.builder().classesId(classes.getId()).teacherId(createReqVO.getClassInstructorName()).teacherUserType(2).build();
        classesTeacherMapper.insert(build);
        classesTeacherMapper.insert(build1);
        // 返回
        adminUserApi.saveUserCollegeData(SecurityFrameworkUtils.getLoginUserId(), 3, createReqVO.getProfessionId(), classes.getId());
        adminUserApi.initUserCollegeData(SecurityFrameworkUtils.getLoginUserId());
        return classes.getId();
    }

    private String getCodeString(ClassesCreateReqVO createReqVO) {
        String str = createReqVO.getClassesGrade();
        // 获取父级代码
        ProfessionsDO professionsDO = professionsMapper.selectById(createReqVO.getProfessionId());

        // 获取流水号
        ClassesDO classesDO = classesMapper.selectOne(new LambdaQueryWrapper<ClassesDO>().orderByDesc(ClassesDO::getClassesCounter).last(" limit 1"));
        int classesCounter = 0;
        if (ObjectUtil.isNotNull(classesDO)) {
            classesCounter = classesDO.getClassesCounter();
        }
        classesCounter += 1;
        str += professionsDO.getProfessionCode() + classesCounter;
        return str;
    }

    @Override
    public void updateClasses(ClassesUpdateReqVO updateReqVO) {
        final Long count = classesMapper.selectCount(new LambdaQueryWrapper<ClassesDO>()
                .eq(ClassesDO::getProfessionId, updateReqVO.getProfessionId())
                .eq(ClassesDO::getClassesName, updateReqVO.getClassesName())
                .ne(ClassesDO::getId, updateReqVO.getId()));
        if (ObjectUtil.isNotNull(count) && count > 0) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.CLASSES_NAME_HAVE_EXISTS);
        }
        // 校验存在
        this.validateClassesExists(updateReqVO.getId());
        // 更新
        ClassesDO updateObj = ClassesConvert.INSTANCE.convert(updateReqVO);
        classesMapper.updateById(updateObj);


        // 修改班主任和辅导员的信息
        ClassesTeacherDO build = ClassesTeacherDO.builder().classesId(updateReqVO.getId()).teacherUserType(1).build();
        ClassesTeacherDO classesTeacherDO = classesTeacherMapper.selectOne(new QueryWrapper(build));
        if (Objects.nonNull(classesTeacherDO)) {
            classesTeacherDO.setTeacherId(updateReqVO.getClassTeacherName());
            classesTeacherMapper.updateById(classesTeacherDO);
        } else {
            classesTeacherMapper.insert(build);
        }

        ClassesTeacherDO build1 = ClassesTeacherDO.builder().classesId(updateReqVO.getId()).teacherUserType(2).build();
        ClassesTeacherDO classesTeacherDO1 = classesTeacherMapper.selectOne(new QueryWrapper(build1));
        if (Objects.nonNull(classesTeacherDO1)) {
            classesTeacherDO1.setTeacherId(updateReqVO.getClassInstructorName());
            classesTeacherMapper.updateById(classesTeacherDO1);
        } else {
            classesTeacherMapper.insert(build1);
        }

        adminUserApi.initUserCollegeData(SecurityFrameworkUtils.getLoginUserId());
    }

    @Override
    public void deleteClasses(String id) {
        // 校验存在
        this.validateClassesExists(id);

        if (ObjectUtil.isNotNull(adminUserApi.checkRoleUser(id).getData()) && adminUserApi.checkRoleUser(id).getData()) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.CHECK_USE_EXISTS);
        }
        // 删除
        classesMapper.deleteById(id);

        // 删除班级中的教师信息
        classesTeacherMapper.delete(new LambdaQueryWrapperX<ClassesTeacherDO>().eq(ClassesTeacherDO::getClassesId, id));
    }

    private void validateClassesExists(String id) {
        if (classesMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.CLASSES_NOT_EXISTS);
        }
    }

    @Override
    @DataPermission(enable = false)
    public ClassesDO getClasses(String id) {

        ClassesDO classesDO = classesMapper.selectById(id);
        // 设置 专业、系部昵称
        if (ObjectUtil.isNotNull(classesDO)) {
            ClassesInfoDO classesInfoDOS = classesMapper.selectClassBaseInfoByClassesIdSelectOne(classesDO.getId());
            classesDO.setDepartmentsId(classesInfoDOS.getDepartmentsId());
            classesDO.setCollegeId(classesInfoDOS.getCollegeId());
        }

        return classesDO;
    }

    @Override
    public List<ClassesDO> getClassesList(Collection<String> ids) {
        return CollectionUtils.isEmpty(ids) ? Collections.emptyList() : classesMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<ClassesDO> getClassesPage(ClassesPageReqVO pageReqVO) {
        if (StringUtil. isNotEmpty(pageReqVO.getOpeningEndTime())) {
           pageReqVO.setOpeningEndTimeDate(DateChangeUtil.stringToDateEnd( pageReqVO.getOpeningEndTime()));
        }
        if (StringUtil. isNotEmpty(pageReqVO.getOpeningStartTime())) {
           pageReqVO.setOpeningStartDate(DateChangeUtil.stringToDateEnd( pageReqVO.getOpeningStartTime()));
        }

         PageResult<ClassesDO> resPage = classesMapper.selectPage0(pageReqVO);
        if (CollectionUtil.isNotEmpty(resPage.getList())) {
            resPage.getList().forEach(item -> {
                Long selectCount = studentRollMapper.selectCount(new LambdaQueryWrapper<StudentRollDO>().eq(StudentRollDO::getClassesId, item.getId()));
                item.setStudentCount(selectCount);
            });
        }


        Set<String> teacherIds = CollectionUtils.convertSet(resPage.getList(), ClassesDO::getClassTeacherName);
        Set<String> teacher2Ids = CollectionUtils.convertSet(resPage.getList(), ClassesDO::getClassInstructorName);
        teacherIds.addAll(teacher2Ids);
        if (CollectionUtil.isNotEmpty(teacherIds)) {
            List<TeacherTeachersDO> teacherTeachersDOS = teacherTeachersMapper.selectBatchIds(teacherIds);
            Map<String, TeacherTeachersDO> stringClassesTeacherDOMap = CollectionUtils.convertMap(teacherTeachersDOS, TeacherTeachersDO::getId);
            resPage.getList().forEach(item -> {
                item.setClassTeacherName(Optional.ofNullable(stringClassesTeacherDOMap).map(s -> s.get(item.getClassTeacherName())).map(TeacherTeachersDO::getTeacherName).orElse(""));
                item.setClassInstructorName(Optional.ofNullable(stringClassesTeacherDOMap).map(s -> s.get(item.getClassInstructorName())).map(TeacherTeachersDO::getTeacherName).orElse(""));
            });
        }
        return resPage;
    }

    @Override
    public List<ClassesDO> getClassesList(ClassesExportReqVO exportReqVO) {
        return classesMapper.selectList0(exportReqVO);
    }

    @Override
    public List<ClassesDO> getClassesListByProfessionsId(String professionsId) {
        return classesMapper.selectList(new LambdaQueryWrapper<ClassesDO>().eq(ClassesDO::getProfessionId, professionsId));
    }

    @Override
    public List<ClassesDO> getClassesListByDepartmentsId(String departmentsId) {
        List<ProfessionsDO> professionsDOS = professionsMapper.selectList(new LambdaQueryWrapper<ProfessionsDO>().eq(ProfessionsDO::getDepartmentsId, departmentsId));
        if (CollectionUtil.isEmpty(professionsDOS)) {
            return new ArrayList<>();
        }
        List<String> collect = professionsDOS.stream().map(s -> s.getId()).collect(Collectors.toList());
        return classesMapper.selectList(new LambdaQueryWrapper<ClassesDO>().in(ClassesDO::getProfessionId, collect));
    }


    @Override
    public List<String> getClassesByTeacherId(String teacherId) {
        return classesTeacherMapper.selectList(new LambdaQueryWrapperX<ClassesTeacherDO>().eqIfPresent(ClassesTeacherDO::getTeacherId, teacherId).select(ClassesTeacherDO::getClassesId)).stream().map(ClassesTeacherDO::getClassesId).collect(Collectors.toList());
    }

    @Override
    public ClassesDO getClassesInfoDTOById(String classesId) {
        return getClassesDO(classesId);
    }

    @Override
    public List<ClassesDO> getClassesInfoDTOListByTeacher(String teacherId) {
        List<ClassesTeacherDO> classesTeacherDOS = classesTeacherMapper.selectList(new LambdaQueryWrapper<ClassesTeacherDO>().eq(ClassesTeacherDO::getTeacherId, teacherId));
        if (CollectionUtil.isEmpty(classesTeacherDOS)) {
            return null;
        }
        return getClassesDOS(classesTeacherDOS);
    }

    @NotNull
    private List<ClassesDO> getClassesDOS(List<ClassesTeacherDO> classesTeacherDOS) {
        List<String> collect = classesTeacherDOS.stream().map(ClassesTeacherDO::getClassesId).distinct().collect(Collectors.toList());
        List<ClassesDO> resList = new ArrayList<>(collect.size());
        collect.forEach(item -> {
            ClassesDO classesDO = getClassesDO(item);
            resList.add(classesDO);
        });
        return resList;
    }

    @Override
    public PageResult<ClassesDO> getClassesInfoDTOPageByTeacher(ClassesInfoDTOPageVO req) {
        if (com.xkcoding.http.util.StringUtil.isNotEmpty(req.getOpeningEndTime())) {
            req.setOpeningEndTimeDate(DateChangeUtil.stringToDateEnd(req.getOpeningEndTime()));
        }
        if (com.xkcoding.http.util.StringUtil.isNotEmpty(req.getOpeningStartTime())) {
            req.setOpeningStartTimeDate(DateChangeUtil.stringToDateStart(req.getOpeningStartTime()));
        }


        PageResult<ClassesTeacherDO> selectPage = classesTeacherMapper.selectPage(req);
        PageResult<ClassesDO> resPage = new PageResult<>();
        if (CollectionUtil.isEmpty(selectPage.getList())) {
            return resPage;
        }

        resPage.setTotal(selectPage.getTotal());
        resPage.setList(getClassesDOS(selectPage.getList()));
        return resPage;
    }


    /**
     * 获取班级详情 设置教师昵称
     *
     * @param classesId
     * @return
     */
    @NotNull
    private ClassesDO getClassesDO(String classesId) {
        ClassesDO classesDO = classesMapper.selectById(classesId);

        privateName(classesId, classesDO);

        List<ClassesTeacherDO> classesTeacherDOS = classesTeacherMapper.selectList(ClassesTeacherDO::getClassesId, classesId);

        if (CollectionUtil.isEmpty(classesTeacherDOS)) {
            return null;
        }//teacherTeachersMapper
        Set<String> teachersIds = CollectionUtils.convertSet(classesTeacherDOS, ClassesTeacherDO::getTeacherId);
        List<TeacherTeachersDO> teacherTeachersDOS = teacherTeachersMapper.selectBatchIds(teachersIds);


        List<ClassesTeacherDTO> classesTeacherDTOS = new ArrayList<>(classesTeacherDOS.size());
        classesTeacherDOS.forEach(item -> {
            ClassesTeacherDTO classesTeacherDTO = new ClassesTeacherDTO();
            BeanUtils.copyProperties(item, classesTeacherDTO);
            classesTeacherDTO.setTeacherUserName(Optional.ofNullable(CollectionUtils.findFirst(teacherTeachersDOS, s -> s.getId().equals(item.getTeacherId()))).map(TeacherTeachersDO::getTeacherName).orElse(""));
            classesTeacherDTOS.add(classesTeacherDTO);
        });
        classesDO.setClassesTeacherDTOS(classesTeacherDTOS);
        classesDO.setStudentCount(studentRollMapper.selectCount(new LambdaQueryWrapper<StudentRollDO>().eq(StudentRollDO::getClassesId, classesId)));
        return classesDO;
    }

    private void privateName(String classesId, ClassesDO classesDO) {
        ClassesInfoDO classesInfoDO = classesMapper.selectClassBaseInfoByClassesIdSelectOne(classesId);
        if (ObjectUtil.isNull(classesInfoDO)) {
            return;
        }
        classesDO.setDepartmentsId(classesInfoDO.getDepartmentsId());
        classesDO.setDepartmentsName(classesInfoDO.getDepartmentsName());
        classesDO.setProfessionId(classesInfoDO.getProfessionsId());
        classesDO.setProfessionsName(classesInfoDO.getProfessionsName());
        classesDO.setCollegeId(classesInfoDO.getCollegeId());
        classesDO.setCollegeName(classesInfoDO.getCollegeName());
        classesDO.setHierarchy(classesInfoDO.getHierarchy());
    }


    @Override
    public List<ClassesInfoDO> selectClassBaseInfoByClassesId(Collection<String> classesIds) {
        return classesMapper.selectClassBaseInfoByClassesId(classesIds);

    }

    @Override
    public ClassesInfoDO getClassesParentInfoDTOByClassesId(String id) {
        return classesMapper.selectClassBaseInfoByClassesIdSelectOne(id);
    }

    @DataPermission(enable = false)
    @Override
    public List<ClassesInfoDO> selectClassesInfoByCollege(Collection<String> collegeIds) {
        return collegesMapper.selectClassesIdByCollege(collegeIds);
    }

    @Override
    public List<ClassesInfoDO> selectClassBaseInfoByProfessionIds(Collection<String> professionIds) {
        return collegesMapper.selectClassesIdByProfession(professionIds);
    }
}
